/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package heuristics;

import java.awt.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.Arrays;
import misc.FOV;
/**
 * (259/225-Cos[x]-Cos[3x]/9-Cos[5x]/25)*225*Pi/(2*259)
 * (10/9-Cos[x]-Cos[3x]/9)*9*Pi/20
 * @author Ahmed
 */
public class AngularRelaxation extends CoverageHeuristic {
    static final int NUMBER_OF_ORIENTATIONS = 1000;
    boolean[][] spottedContinuous;
    int[] camTotal;
    
    public AngularRelaxation(String file) {
        super(file, NUMBER_OF_ORIENTATIONS);
    }
    
    public AngularRelaxation(ArrayList<Rectangle> obstacles, ArrayList<Point2D.Double> cameras, ArrayList<Point2D.Double> people) {
        super(obstacles, cameras, people, NUMBER_OF_ORIENTATIONS,false);
    }
	
    public double f(double[] angles, double x) {
            double ret = 0;
            for (double c : angles)
                    ret += Math.exp(4 * (Math.cos(c - x) - 1));
            return ret;
    }

    public double best(double[] angles) {
            double fmax = 0, xmax = -1, fmax2 = 0;
            for (double c : angles) {
                    double fx = f(angles, c);
                    if (Double.compare(fx, fmax) > 0) {
                            fmax = fx;
                            xmax = c;
                    }
            }
            double h = 0.01;
            while (Double.compare(fmax2 = f(angles, xmax - h), fmax) > 0) {
                    fmax = fmax2;
                    xmax -= h;
            }
            while (Double.compare(fmax2 = f(angles, xmax + h), fmax) > 0) {
                    fmax = fmax2;
                    xmax += h;
            }
            while (xmax > 2 * Math.PI) xmax -= 2 * Math.PI;
            while (xmax < 0) xmax += 2 * Math.PI;
            return xmax;
    }
    
    public double best2(double[] angles) {
        double best = 0;
        double bestAngle = 0;
          for (int orient = 0; orient < number_of_orientations; orient++) {
              double fo = f(angles, orient * delta_angle);
              if (Double.compare(best, fo) < 0) {
                  bestAngle = orient * delta_angle;
                best = fo;
              }
          }
          return bestAngle;
    }

    public int[] reassign() {
//        System.out.println(continuous);
        if (spottedContinuous == null)
            spottedContinuous = new boolean[number_of_cameras][number_of_men];
        for (int camInd = 0; camInd < number_of_cameras; camInd++)
            for (int personInd = 0; personInd < number_of_men; personInd++)
                spottedContinuous[camInd][personInd] = picks(camInd, personInd);
        boolean[] used = new boolean[number_of_cameras];
        boolean[] covered = new boolean[number_of_men];
        double[][] angles = new double[number_of_cameras][];
        assignment = new int[number_of_cameras];
        int greedyCoverage = 0;
        for (int i = 0; i < number_of_cameras; i++) {
           int bestCamInd = -1, bestOrient = -1;
           double best = -1;
           for (int camInd = 0; camInd < number_of_cameras; camInd++) {
              if (used[camInd]) continue;
              int camCount = 0;
              boolean taken [] = new boolean[number_of_men];
              Arrays.fill(taken, false);
              for (int p = 0; p < number_of_men; p++)
                  if (!covered[p] && spottedContinuous[camInd][p]&&!taken[p]){
                      camCount++;
                      taken[p] = true;
                  }
              angles[camInd] = new double[camCount];
              double camX = cameras.get(camInd).x;
              double camY = cameras.get(camInd).y;
              for (int p = 0, k = 0; p < number_of_men; p++) {
                  if (!covered[p] && spottedContinuous[camInd][p]) {
                      angles[camInd][k] = Math.acos((people.get(p).x - camX) / people.get(p).distance(camX, camY));
                      if (people.get(p).y < camY) angles[camInd][k] = 2 * Math.PI - angles[camInd][k];
                      k++;
                  }
              }
              double optAngle = best(angles[camInd]);
              double optCoverage = f(angles[camInd], optAngle);
              int bestCamOrient = (int)(Math.round((optAngle + 0.5 * field_of_view) / delta_angle));
              if (Double.compare(best, 1.0*optCoverage/camCount) < 0) {
                 best = 1.0*optCoverage/camCount;
                 bestOrient = bestCamOrient;
                 bestCamInd = camInd;
              }
           }
           used[bestCamInd] = true;
           assignment[bestCamInd] = bestOrient;
           FOV isovist = getOrientationIsovist(bestCamInd, bestOrient);
           for (int p = 0, k = 0; p < number_of_men; p++)
               if (!covered[p] && spottedContinuous[bestCamInd][p] && isovist.contains(people.get(p))) {
                   covered[p] = true;
                   greedyCoverage++;
               }
        }
        return assignment;
    }

    @Override
    public String toString() {
        return "Angular Relaxation";
    }
}
